package com.zzg.lucene;

import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.IntPoint;
import org.apache.lucene.document.LongPoint;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

public class SearchPage {
	private static List<Passage> psgList = null;

	// 写对象
	private static IndexWriter writer = null;

	// 数据初始化
	static {
		psgList = new ArrayList<Passage>();

		// 产生一堆数据
		for (int i = 1; i <= 200; i++) {
			psgList.add(new Passage(i, "yellowcong", "717350389@qq.com", "逗比", 23, "I LOVE YOU ", new Date()));
		}
	}

	// 删除全部索引
	public static void deleteAll() {
		IndexWriter writer = null;
		try {
			// 获取IndexWriter
			writer = getIndexWriter();

			// 删除所有的数据
			writer.deleteAll();

			int cnt = writer.numDocs();
			System.out.println("索引条数\t" + cnt);

			// 提交事物
			writer.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// coloseWriter(writer);
		}
	}

	// 创建索引目录
	private static String getIndexPath() {
		// 获取索引的目录
		String path = "c:\\lucene\\index";

		// 不存在就创建目录
		File file = new File(path);
		if (!file.exists()) {
			file.mkdirs();
		}
		return path;
	}

	// IndexWrite 创建
	public static IndexWriter getIndexWriter() throws Exception {
		// 创建IdnexWriter
		String path = getIndexPath();
		FSDirectory fs = FSDirectory.open(Paths.get(path));
		if (writer == null) {
			// 创建IndexWriterConfig 对象
			IndexWriterConfig indexWriterConfig = new IndexWriterConfig(new StandardAnalyzer());
			indexWriterConfig.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
			// 创建writer对象
			writer = new IndexWriter(fs, indexWriterConfig);
		}
		return writer;
	}

	// IndexReader 创建
	public static IndexReader getIndexReader() throws Exception {
		// 创建IdnexWriter
		String path = getIndexPath();
		Directory fs = FSDirectory.open(Paths.get(path));
		return DirectoryReader.open(fs);
	}

	// 分页查询方式二:通过IndexSearcher.searchAfter
	public static void queryByPager2(int pageNow, int pageSize) {
		IndexReader reader = null;
		try {
			reader = getIndexReader();

			QueryParser parser = new QueryParser("content", new StandardAnalyzer());

			Query query = parser.parse("username:yellow*");

			// 创建IndexSearcher
			IndexSearcher searcher = new IndexSearcher(reader);

			int start = (pageNow - 1) * pageSize;
			// 查询数据， 结束页面自前的数据都会查询到，但是只取本页的数据
			TopDocs topDocs = searcher.search(query, start);
			// 获取到上一页最后一条
			ScoreDoc preScore = topDocs.scoreDocs[start - 1];

			// 查询最后一条后的数据的一页数据
			topDocs = searcher.searchAfter(preScore, query, pageSize);
			ScoreDoc[] scores = topDocs.scoreDocs;

			System.out.println("查询到的条数\t" + topDocs.totalHits);
			// 读取数据
			for (int i = 0; i < scores.length; i++) {
				Document doc = reader.document(scores[i].doc);
				System.out.println(doc.get("id") + ":" + doc.get("username") + ":" + doc.get("email"));
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			coloseReader(reader);
		}
	}
	// 分页查询方式一:通过查询总数再分页
	 public static void queryByPager1(int pageNow, int pageSize) {
	        IndexReader reader = null;
	        try {
	            reader = getIndexReader();

	            QueryParser parser = new QueryParser("content", new StandardAnalyzer());

	            Query query = parser.parse("username:yellow*");

	            // 创建IndexSearcher
	            IndexSearcher searcher = new IndexSearcher(reader);

	            // 查询数据， 结束页面自前的数据都会查询到，但是只取本页的数据
	            TopDocs topDocs = searcher.search(query, pageSize * pageNow);

	            // searcher.searchAfter(after, query, n)
	            System.out.println("查询到的条数\t" + topDocs.totalHits);
	            ScoreDoc[] scores = topDocs.scoreDocs;

	            int start = (pageNow - 1) * pageSize;
	            int end = pageSize * pageNow;
	            for (int i = start; i < end; i++) {
	                Document doc = reader.document(scores[i].doc);
	                System.out.println(doc.get("id") + ":" + doc.get("username") + ":" + doc.get("email"));
	            }
	        } catch (Exception e) {
	            e.printStackTrace();
	        } finally {
	            coloseReader(reader);
	        }
	    }
	 

	 
	public static void main(String[] args) {
		// 删除 所有索引
		deleteAll();
		// 建立索引
		index();

		// 分页方式一：
		queryByPager1(1,1);
		// 分页方式二:
		//queryByPager2(1,1);
	}

	// 创建IndexWriter
	public static void index() {
		IndexWriter writer = null;
		try {
			// 1、获取IndexWriter
			writer = getIndexWriter();

			// 2、建立索引
			for (Passage psg : psgList) {
				Document doc = new Document();

				// IntField 不能直接检索到，需要结合
				doc.add(new IntPoint("id", psg.getId()));

				// 用户String类型的字段的存储，StringField是只索引不分词
				doc.add(new TextField("username", psg.getUsername(), Field.Store.YES));

				// 主要对int类型的字段进行存储，需要注意的是如果需要对InfField进行排序使用SortField.Type.INT来比较，如果进范围查询或过滤，需要采用NumericRangeQuery.newIntRange()
				doc.add(new IntPoint("age", psg.getAge()));

				// 对String类型的字段进行存储，TextField和StringField的不同是TextField既索引又分词
				doc.add(new TextField("content", psg.getContent(), Field.Store.NO));

				doc.add(new StringField("keyword", psg.getKeyword(), Field.Store.YES));

				doc.add(new StringField("email", psg.getEmail(), Field.Store.YES));

				// 日期数据添加索引
				doc.add(new LongPoint("addDate", psg.getAddDate().getTime()));

				// 3、添加文档
				writer.addDocument(doc);
			}

			// 索引条数
			int cnt = writer.numDocs();
			System.out.println("索引条数\t" + cnt);

			// 提交事物
			writer.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			coloseWriter(writer);
		}
	}

	// 关闭IndexWriter 对象
	private static void coloseWriter(IndexWriter writer) {
		try {
			if (writer != null) {
				writer.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	// 关闭IndexReader 对象
	private static void coloseReader(IndexReader reader) {
		try {
			if (reader != null) {
				reader.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	static class Passage {
		private int id;
		private String username;
		private String email;
		private String keyword;
		private int age;
		// 这个模拟的是文章
		private String content;
		private Date addDate;

		public Passage(int id, String username, String email, String keyword, int age, String content, Date addDate) {
			super();
			this.id = id;
			this.username = username;
			this.email = email;
			this.keyword = keyword;
			this.age = age;
			this.content = content;
			this.addDate = addDate;
		}

		public int getId() {
			return id;
		}

		public void setId(int id) {
			this.id = id;
		}

		public String getUsername() {
			return username;
		}

		public void setUsername(String username) {
			this.username = username;
		}

		public String getEmail() {
			return email;
		}

		public void setEmail(String email) {
			this.email = email;
		}

		public String getKeyword() {
			return keyword;
		}

		public void setKeyword(String keyword) {
			this.keyword = keyword;
		}

		public int getAge() {
			return age;
		}

		public void setAge(int age) {
			this.age = age;
		}

		public String getContent() {
			return content;
		}

		public void setContent(String content) {
			this.content = content;
		}

		public Date getAddDate() {
			return addDate;
		}

		public void setAddDate(Date addDate) {
			this.addDate = addDate;
		}
	}

}
